﻿
namespace Aeon.Emulator.Instructions.Arithmetic
{
    internal static class Mul
    {
        [Opcode("F6/4 rmb", OperandSize = 16 | 32, AddressSize = 16 | 32)]
        public static void ByteMultiply(Processor p, byte multiplicand)
        {
            p.AX = (short)((ushort)p.AL * multiplicand);
            if(p.AH == 0)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }

        [Opcode("F7/4 rmw", AddressSize = 16 | 32)]
        public static void WordMultiply(Processor p, ushort multiplicand)
        {
            uint fullResult = ((uint)(ushort)p.AX) * (uint)multiplicand;
            p.AX = (short)(fullResult & 0xFFFF);
            p.DX = (short)(fullResult >> 16);
            if(p.DX == 0)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }
        [Alternate("WordMultiply", AddressSize = 16 | 32)]
        public static void DWordMultiply(Processor p, uint multiplicand)
        {
            ulong fullResult = ((ulong)(uint)p.EAX) * (ulong)multiplicand;
            p.EAX = (int)(fullResult & 0xFFFFFFFF);
            p.EDX = (int)(fullResult >> 32);
            if(p.EDX == 0)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }
    }
    internal static class IMul
    {
        [Opcode("F6/5 rmb", OperandSize = 16 | 32, AddressSize = 16 | 32)]
        public static void ByteMultiply(Processor p, sbyte multiplicand)
        {
            p.AX = (short)((sbyte)p.AL * multiplicand);
            if(p.AH == 0 || p.AH == 0xFF)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }
        [Opcode("F7/5 rmw", AddressSize = 16 | 32)]
        public static void WordMultiply(Processor p, short multiplicand)
        {
            int fullResult = (int)p.AX * (int)multiplicand;
            p.AX = (short)(fullResult & 0xFFFF);
            p.DX = (short)(fullResult >> 16);
            if(p.DX == 0 || p.DX == -1)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }
        [Alternate("WordMultiply", AddressSize = 16 | 32)]
        public static void DWordMultiply(Processor p, int multiplicand)
        {
            long fullResult = (long)p.EAX * (long)multiplicand;
            p.EAX = (int)(fullResult & 0xFFFFFFFF);
            p.EDX = (int)(fullResult >> 32);
            if(p.EDX == 0 || p.EDX == -1)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= EFlags.Carry | EFlags.Overflow;
        }

        [Opcode("0FAF/r rw,rmw", AddressSize = 16 | 32)]
        public static void WordMultiply2(Processor p, ref short value1, short value2)
        {
            int temp = (int)value1 * (int)value2;
            value1 = (short)temp;

            if(temp >= short.MinValue && temp <= short.MaxValue)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= (EFlags.Carry | EFlags.Overflow);
        }
        [Alternate("WordMultiply2", AddressSize = 16 | 32)]
        public static void DWordMultiply2(Processor p, ref int value1, int value2)
        {
            long temp = (long)value1 * (long)value2;
            value1 = (int)temp;

            if(temp >= int.MinValue && temp <= int.MaxValue)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= (EFlags.Carry | EFlags.Overflow);
        }

        [Opcode("6B/r rw,rmw,ibx|69/r rw,rmw,iw", AddressSize = 16 | 32)]
        public static void WordMultiply3(Processor p, out short result, short multiplicand1, short multiplicand2)
        {
            int temp = (int)multiplicand1 * (int)multiplicand2;
            result = (short)temp;

            if(temp >= short.MinValue && temp <= short.MaxValue)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= (EFlags.Carry | EFlags.Overflow);
        }
        [Alternate("WordMultiply3", AddressSize = 16 | 32)]
        public static void DWordMultiply3(Processor p, out int result, int multiplicand1, int multiplicand2)
        {
            long temp = (long)multiplicand1 * (long)multiplicand2;
            result = (int)temp;

            if(temp >= int.MinValue && temp <= int.MaxValue)
                p.Flags &= ~(EFlags.Carry | EFlags.Overflow);
            else
                p.Flags |= (EFlags.Carry | EFlags.Overflow);
        }
    }
}
